<template>
  <Card title="代码生成" size="small">
    <template #extra>
      <Row>
        <Col style="margin-right: 10px"> <Input placeholder="请输入主类名称" v-model:value="className" /> </Col>
        <Col class="btn-group" style="margin-right: -15px">
          <Button type="primary" @click="BuildClass"><BuildFilled /> 生成</Button>
          <Button @click="onCopyCodes" :disabled="target.length == 0"><CopyFilled /> 复制</Button>
        </Col>
      </Row>
    </template>
    <Row :gutter="10">
      <Col :span="10">
        <Input.TextArea :rows="bodyHeight / 20.5" v-model:value="source" />
      </Col>
      <Col :span="14">
        <Input.TextArea :rows="bodyHeight / 20.5" v-model:value="target" :readonly="true" />
      </Col>
    </Row>
  </Card>
</template>
<script setup>
  import { useStore } from 'vuex';
  import { ref, inject, computed, watch } from 'vue';
  import { Card, Row, Col, Button, Input } from 'ant-design-vue';
  import { BuildFilled, CopyFilled } from '@ant-design/icons-vue';

  const $store = useStore();
  const $message = inject('$message');
  const $copyText = inject('$copyText');

  const classes = [];
  const source = ref('');
  const target = ref('');
  const className = ref('');

  const bodyHeight = computed(() => {
    return $store.state.area.content.height - 140;
  });

  watch(source, value => {
    try {
      let json = JSON.parse(value);

      if (json) {
        source.value = JSON.stringify(json, null, 2);
      }
    } catch {}
  });

  function onCopyCodes() {
    $copyText(target.value).then(() => {
      $message.success('代码已复制！');
    });
  }

  function BuildClass() {
    if (!className.value) {
      $message.warning('请输入主类名');

      return;
    }

    let data = JSON.parse(source.value);
    let clsName = className.value.substring(0, 1).toUpperCase() + className.value.substring(1);

    let props = Object.keys(data);
    let builds = [`public class ${clsName} \r\n{`];

    builds.push('\t#region Properties\r\n');

    classes.length = 0;

    props.forEach(p => {
      let cType = 'string';
      let type = typeof data[p];
      let p1 = p.substring(0, 1).toUpperCase() + p.substring(1);

      if (type == 'number') {
        cType = p.endsWith('Amount') ? 'decimal' : Number.isInteger(data[p]) ? 'int' : 'decimal';
      } else if (type == 'boolean') {
        cType = 'bool';
      } else if (p.endsWith('Time') || p.endsWith('Date')) {
        cType = data[p] ? 'DateTime' : 'DateTime?';
      }

      if (type == 'object') {
        let complexType = p1;

        if (Array.isArray(data[p])) {
          let itemType = typeof data[p][0];

          if (itemType == 'string') {
            cType = 'IList<string>';
          } else if (itemType == 'boolean') {
            cType = 'IList<bool>';
          } else if (itemType == 'number') {
            cType = Number.isInteger(data[p][0]) ? 'int' : 'decimal';
          } else {
            if (p1.endsWith('ies')) {
              complexType = p1.substring(0, p1.length - 3) + 'y';
            } else {
              complexType = p1.substring(0, p1.length - 1);
            }

            Resolves(data[p], complexType);

            cType = `IList<${complexType}>`;
          }
        } else {
          Resolves(data[p], p1);

          cType = p1;
        }
      }

      builds.push(`\t[JsonProperty("${p}")]\r\n\tpublic ${cType} ${p1} { get; set; }\r\n`);
    });

    builds.push('\t#endregion');
    builds.push('}');

    classes.push(builds.join('\r\n'));

    target.value = classes.join('\r\n\r\n');
  }

  function Resolves(data, name) {
    if (Array.isArray(data)) {
      data = data[0];
    }

    if (!data) {
      return;
    }

    let props = Object.keys(data);
    let builds = [`public class ${name} \r\n{`];

    builds.push('\t#region Properties\r\n');

    props.forEach(p => {
      let cType = 'string';
      let type = typeof data[p];
      let p1 = p.substring(0, 1).toUpperCase() + p.substring(1);

      if (type == 'number') {
        cType = p.endsWith('Amount') ? 'decimal' : Number.isInteger(data[p]) ? 'int' : 'decimal';
      } else if (type == 'boolean') {
        cType = 'bool';
      } else if (p.endsWith('Time') || p.endsWith('Date')) {
        cType = data[p] ? 'DateTime' : 'DateTime?';
      }

      if (type == 'object') {
        let complexType = p1;

        if (Array.isArray(data[p])) {
          let itemType = typeof data[p][0];

          if (itemType == 'string') {
            cType = 'IList<string>';
          } else if (itemType == 'boolean') {
            cType = 'IList<bool>';
          } else if (itemType == 'number') {
            cType = Number.isInteger(data[p][0]) ? 'int' : 'decimal';
          } else {
            if (p1.endsWith('ies')) {
              complexType = p1.substring(0, p1.length - 3) + 'y';
            } else {
              complexType = p1.substring(0, p1.length - 1);
            }

            Resolves(data[p], complexType);

            cType = `IList<${complexType}>`;
          }
        } else {
          Resolves(data[p], p1);

          cType = p1;
        }
      }

      builds.push(`\t[JsonProperty("${p}")]\r\n\tpublic ${cType} ${p1} { get; set; }\r\n`);
    });

    builds.push('\t#endregion');
    builds.push('}');

    classes.push(builds.join('\r\n'));
  }
</script>
